package concurrency.part2.task1;

import concurrency.Function;

import java.util.concurrent.*;

public class Main {
    public static final Function sin = new Function() {
        @Override
        public double call(double x) {
            return Math.sin(x);
        }
    };

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        int n = 20000;
        int maxRank = 8;
        System.out.println("Sum of sin(x) where x from " + -n + " to " + n + " on is: " + SeriesEval.eval(sin, -n, n, 1, maxRank) + " " + n);
    }
}


class SeriesEval implements Callable<Double> {
    private Function function;
    private double startX, endX, stepX;

    private SeriesEval(Function function, double startX, double endX, double stepX) {
        this.function = function;
        this.startX = startX;
        this.endX = endX;
        this.stepX = stepX;
    }

    public static double eval(Function f, double startX, double endX, double step, int maxRank) {
        double taskStep = (endX - startX) / maxRank;

        Future<Double> tasks[] = new Future[maxRank];
        ExecutorService executor = Executors.newFixedThreadPool(maxRank);

        for (int i = 0; i < maxRank; i++, startX += taskStep) {
            tasks[i] = executor.submit(new SeriesEval(f, startX, i == maxRank - 1 ? Math.max(startX + taskStep, endX + step) : startX + taskStep, step));
        }

        double sum = 0;
        for (Future<Double> task : tasks) {
            try {
                sum += task.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        return sum;
    }

    @Override
    public Double call() throws Exception {
        double sum = 0;
        for (double x = startX; x < endX; x += stepX) {
            sum += function.call(x);
        }

        return sum;
    }
}